package com.oswift.utils.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.oswift.utils.common.StreamUtil;
import com.oswift.utils.common.XMLParseUtil;
import com.oswift.utils.exception.ErrorCode;
import com.oswift.utils.exception.PlatException;

/**
 *
 * 该类用于向服务器发送请求，从响应流中获取数据
 *
 * @author Administrator
 * @version C03 Oct 27, 2012
 * @since OSwift GPM V1.0
 */
public final class PostURL
{
    /**
     * 日志对象
     */
    private static Logger log = LoggerFactory.getLogger(PostURL.class);

    /**
     * document
     */
    private static final String DOCUMENT = "document";

    /**
     * xmlString
     */
    private static final String XMLSTRING = "xmlString";

    /**
     * 构造函数
     */
    private PostURL()
    {
    }

    /**
     *
     * 发送一个url请求，得到响应流，并构造文本对象
     *
     * @param urlStr
     *            待请求的url
     * @param param
     *            param
     * @param properties
     *            properties
     * @return HttpURLConnection HttpURLConnection
     * @throws PlatException
     *             PlatException
     */
    public static HttpURLConnection sendHttpRequest(String urlStr,
            String param, Map<String, String> properties) throws PlatException
    {
        OutputStream os = null;
        try
        {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();

            if (null == connection)
            {
                log.error("Fail to open http connection, url=" + urlStr
                        + ", param=" + param);
                throw new PlatException(
                        ErrorCode.COMMON_OPEN_HTTP_CONNECTION_FAIL);
            }

            // 设置请求超时时间为60秒
            connection.setReadTimeout(60000);

            // 设置请求方式为post
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept-Language", "utf-8");
            connection.setRequestProperty("Content-Type", "text/xml");
            connection.setRequestProperty("connection", "Keep-Alive");
            if (null != properties && !properties.isEmpty())
            {
                for (Entry<String, String> entry : properties.entrySet())
                {
                    connection.setRequestProperty(entry.getKey(), entry
                            .getValue());
                }
            }

            // 然后把连接设为输出模式。URLConnection通常作为输入来使用，比如下载一个Web页。
            // 通过把URLConnection设为输出，可以把数据向你个Web页传送。下面是如何做：
            connection.setDoOutput(true);
            connection.setDoInput(true);

            if (param == null || "".equals(param))
            {
                // 如果param为空，则发送get请求
                connection.setRequestMethod("GET");
            }
            else
            {
                os = connection.getOutputStream();

                // 将参数放入输出流
                os.write(param.getBytes("utf-8"));
                os.flush();
            }

            return connection;
        }
        catch (IOException e)
        {
            log.error("Fail to request [" + urlStr + "], param is [" + param
                    + "].", e);
            throw new PlatException(ErrorCode.COMMON_SEND_HTTP_REQUEST_FAIL, e);
        }
        finally
        {
            StreamUtil.getInstance().close(os);
        }
    }

    /**
     * 发送一个url请求，得到响应流，并构造文本对象
     *
     * @param urlStr
     *            待请求的url
     * @param param
     *            请求参数
     * @return 文本对象
     * @throws PlatException
     *             通用异常
     */
    public static Map<Object, Object> sendURL(String urlStr, String param)
        throws PlatException
    {
        OutputStream os = null;
        Map<Object, Object> map = null;
        try
        {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();

            if (connection == null)
            {
                log.error("Fail to open http connection, url=" + urlStr
                        + ", param=" + param);
                throw new PlatException(
                        ErrorCode.COMMON_OPEN_HTTP_CONNECTION_FAIL);
            }

            // 设置请求超时时间为60秒
            connection.setReadTimeout(60000);

            // 设置请求方式为post
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept-Language", "utf-8");
            connection.setRequestProperty("Content-Type", "text/xml");
            connection.setRequestProperty("connection", "Keep-Alive");

            // 然后把连接设为输出模式。URLConnection通常作为输入来使用，比如下载一个Web页。
            // 通过把URLConnection设为输出，可以把数据向你个Web页传送。下面是如何做：
            connection.setDoOutput(true);
            connection.setDoInput(true);

            if (param == null || "".equals(param))
            {
                // 如果param为空，则发送get请求
                connection.setRequestMethod("GET");
            }
            else
            {
                os = connection.getOutputStream();

                // 将参数放入输出流
                os.write(param.getBytes("utf-8"));
                os.flush();
            }

            String xmlString = getRspString(connection);
            Document document = XMLParseUtil.parseXml2Docment(xmlString);

            map = new HashMap<Object, Object>();

            map.put(XMLSTRING, xmlString);
            map.put(DOCUMENT, document);

        }
        catch (IOException e)
        {
            log.error("Fail to request [" + urlStr + "], param is [" + param
                    + "].", e);
            throw new PlatException(ErrorCode.COMMON_SEND_HTTP_REQUEST_FAIL, e);
        }
        finally
        {
            StreamUtil.getInstance().close(os);
        }

        return map;
    }

    /**
     * 从http连接中获取xml文档
     *
     * @param connection
     *            http连接
     * @return 文本对象
     * @throws PlatException
     *             通用异常
     */
    private static String getRspString(HttpURLConnection connection)
        throws PlatException
    {
        InputStream is = null;
        BufferedReader br = null;

        StringBuilder xmlString = new StringBuilder();
        try
        {
            // 得到输入流
            is = connection.getInputStream();
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            String curLine = null;

            // 从输入流中读取返回结果
            while ((curLine = br.readLine()) != null)
            {
                xmlString.append(curLine.trim());
            }

            log.debug("Get response from update server is :"
                    + xmlString.toString());
        }
        catch (Exception e1)
        {
            log.error("Fail to get xml message from HttpURLConnection", e1);
            throw new PlatException(ErrorCode.COMMON_OPERATE_STREAM_FAIL, e1);
        }
        finally
        {
            StreamUtil.getInstance().close(br, is);
            StreamUtil.getInstance().disconnect(connection);
        }

        return xmlString.toString();
    }

    /**
     *
     * 发送一个url请求，得到响应流，并构造文本对象
     *
     * @param urlStr
     *            待请求的url
     * @param param
     *            请求参数
     * @param properties
     *            消息头属性
     * @return Document
     * @throws PlatException
     *             PlatException
     */
    public static Document sendPostURL(String urlStr, String param,
            Map<String, String> properties) throws PlatException
    {
        OutputStream os = null;
        try
        {
            URL url = new URL(urlStr);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();

            if (connection == null)
            {
                log.error("Fail to open http connection, url=" + urlStr
                        + ", param=" + param);
                throw new PlatException(
                        ErrorCode.COMMON_OPEN_HTTP_CONNECTION_FAIL);
            }

            // 设置请求超时时间为60秒
            connection.setReadTimeout(60000);

            // 设置请求方式为post
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Accept-Language", "utf-8");
            connection.setRequestProperty("Content-Type", "text/xml");
            connection.setRequestProperty("connection", "Keep-Alive");
            if (null != properties && !properties.isEmpty())
            {
                for (Entry<String, String> entry : properties.entrySet())
                {
                    connection.setRequestProperty(entry.getKey(), entry
                            .getValue());
                }
            }

            // 然后把连接设为输出模式。URLConnection通常作为输入来使用，比如下载一个Web页。
            // 通过把URLConnection设为输出，可以把数据向你个Web页传送。下面是如何做：
            connection.setDoOutput(true);
            connection.setDoInput(true);

            if (param == null || "".equals(param))
            {
                // 如果param为空，则发送get请求
                connection.setRequestMethod("GET");
            }
            else
            {
                os = connection.getOutputStream();

                // 将参数放入输出流
                os.write(param.getBytes("utf-8"));
                os.flush();
            }

            return getDocFromHttpConnection(connection);
        }
        catch (IOException e)
        {
            log.error("Fail to request [" + urlStr + "], param is [" + param
                    + "].", e);
            throw new PlatException(ErrorCode.COMMON_SEND_HTTP_REQUEST_FAIL, e);
        }
        finally
        {
            StreamUtil.getInstance().close(os);
        }
    }

    /**
     * 从http连接中获取xml文档
     *
     * @param connection
     *            http连接
     * @return 文本对象
     * @throws PlatException
     *             通用异常
     */
    public static Document getDocFromHttpConnection(HttpURLConnection connection)
        throws PlatException
    {
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder xmlBuilder = new StringBuilder();

        try
        {
            // 得到输入流
            is = connection.getInputStream();
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            String curLine = null;

            // 从输入流中读取返回结果
            while ((curLine = br.readLine()) != null)
            {
                xmlBuilder.append(curLine.trim());
            }

            log.debug("Get response from update server is :"
                    + xmlBuilder.toString());
        }
        catch (Exception e1)
        {
            log.error("Fail to get xml message from HttpURLConnection", e1);
            throw new PlatException(ErrorCode.COMMON_OPERATE_STREAM_FAIL, e1);
        }
        finally
        {
            StreamUtil.getInstance().close(br, is);
            StreamUtil.getInstance().disconnect(connection);
        }

        return XMLParseUtil.parseXml2Docment(xmlBuilder.toString());
    }

    /**
     * 从http请求中获取xml文档
     *
     * @param req
     *            HTTP请求对象
     * @return xml文档对象
     * @throws PlatException
     *             通用异常
     */
    public static Document getDocFromHttpRequest(HttpServletRequest req)
        throws PlatException
    {
        InputStream is = null;
        BufferedReader br = null;
        StringBuilder xmlBuilder = new StringBuilder();

        try
        {
            // 从请求中获取输入流
            is = req.getInputStream();
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            String curLine = null;

            // 从输入流中读取返回结果
            while ((curLine = br.readLine()) != null)
            {
                xmlBuilder.append(curLine.trim());
            }
        }
        catch (Exception e1)
        {
            log.error("Fail to get xml message from HttpServletRequest.", e1);
            throw new PlatException(ErrorCode.COMMON_OPERATE_STREAM_FAIL, e1);
        }
        finally
        {
            StreamUtil.getInstance().close(br, is);
        }

        return XMLParseUtil.parseXml2Docment(xmlBuilder.toString());
    }

    /**
     *
     * 从http请求中获取xml字符串
     *
     * @param req
     *            HTTP请求对象
     * @return XML字符串
     * @throws PlatException
     *             PlatException
     */
    public static String getContent(HttpServletRequest req) throws PlatException
    {
        if (null == req)
        {
            return null;
        }

        InputStream is = null;
        BufferedReader br = null;
        StringBuilder temp = new StringBuilder();

        try
        {
            // 从请求中获取输入流
            is = req.getInputStream();
            br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            String curLine = null;

            // 从输入流中读取返回结果
            while ((curLine = br.readLine()) != null)
            {
                temp.append(curLine.trim());
            }
        }
        catch (Exception e1)
        {
            log.error("Fail to get xml message from HttpServletRequest.", e1);
            throw new PlatException(ErrorCode.COMMON_OPERATE_STREAM_FAIL, e1);
        }
        finally
        {
            StreamUtil.getInstance().close(br, is);
        }
        return temp.toString();
    }
}
